package org.kolonitsky.alexey.utils
{
    /**
     *
     */
	public class ArrayUtils
	{
        /**
         *  Get count of randomly items from array.
         *  @param array source items
         *  @param count is an number of result array
         *
         *  @return array with count randomly items from source array.
         */
		public static function shuffleTo (array:Array, count:int = -1):Array 
		{
			var n:int = count == -1 ? array.length : count;
			var temp:Array = array.slice();
			var result:Array = new Array(count);
			for (var i:int = 0; i < n; ++i)
				result[i] = temp.splice(Math.floor(Math.random() * temp.length), 1)[0];
			return result;
		}
		
        /**
         *  shuffle all items in array
         *  @param array which shaffled.
         */
		public static function shuffle (array:Array):void
		{
            if (array == null)
                return;
            
            var n:int = array.length;
            if (n < 2)
                return;
            
			for(var i:int = 0; i < n; ++i)
			{
				var tmp:* = array[i];
				var randomNum:int = int(Math.random() * n);
				array[i] = array[randomNum];
				array[randomNum] = tmp;
			}
		}


        //--------------------------------------------------------------------
        // Array set methods
        //--------------------------------------------------------------------

        public static function union (a:Array, b:Array):Array
        {
            var result:Array = a.splice(0);
            var n:int = b.length;
            for (var i:int = 0; i < n; ++i)
                if (result.indexOf(b[i]) == -1)
                    result.push(b[i]);
            return result;
        }

        public static function intersect(a:Array, b:Array):Array
        {
            var result:Array = [];
            var n:int = a.length;
            for (var i:int = 0; i < n; ++i)
                if (b.indexOf(a[i]) != -1)
                    result.push(a[i]);
            return result;
        }

        /**
         *  Find all items by one property value
         *
         *  @param source is source array
         *  @param propertyName item's property name
         *  @param propertyValue item's property value
         *
         *  @return source of all item witch property equal to propertyValue.
         */
        public static function getItemsByProperty(source:Array, propertyName:String, propertyValue:String):Array
        {
            var result:Array = [];
            var n:int = source.length;
            for (var i:int = 0; i < n; ++i)
                if (source[i][propertyName] == propertyValue)
                    result.push(source[i]);
            return result;
        }

        /**
         *  Filter one item by it property value
         *
         *  @param source is source array
         *  @param propertyName item's property name
         *  @param propertyValue item's property value
         *
         *  @return source of all item witch property equal to propertyValue.
         */
        public static function getItemByProperty(source:*,  propertyName:String, propertyValue:String):Object
        {
            var n:int = source.length;
            for (var i:int = 0; i < n; ++i)
                if (source[i][propertyName] == propertyValue)
                    return source[i];
            return null
        }

        /**
         * Collect one property from each item in array. All collected properties
         * returned as result.
         *
         * @param array
         * @param propertyName
         * @return
         */
        public static function getItemProperties(array:*, propertyName:String):Array
        {
            var result:Array = new Array(array.length);
            for (var i:int = 0; i < array.length; i++)
            {
                var item:Object = array[i];
                if (propertyName in item)
                    result[i] = item[propertyName];
            }
            return result;
        }

        public static function toArray(iterable:*):Array
        {
            var result:Array = [];
            for each (var elem:* in iterable)
                result.push(elem);
            return result;
        }

        public static function quickSearchById(array:*,
            propertyName:String, value:Object):int
        {
            if (array == null || propertyName == null || propertyName == "")
                throw new Error("Incorrect input parameters");

            var first:int = 0, last:int = array.length, mid:int = 0;

            if (last == 0)
                return -1;
            else if (array[0][propertyName] > value)
                return -1;
            else if (array[last - 1][propertyName] < value)
                return -1;

            while (first < last)
            {
                mid = first + (last - first) / 2;

                if (value <= array[mid][propertyName])
                    last = mid;
                else
                    first = mid + 1;
            }

            return last;
        }
    }
}